/*
*
* Created by yuri at Apr 2, 2011
*
*/



package implementation.server;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.log4j.Logger;

import implementation.shared.EPacketParam;
import implementation.shared.EPacketType;
import implementation.shared.INotification;
import implementation.shared.IPacket;
import implementation.shared.SharedFactory;
import implementation.shared.stubs.IUserStub;

public class SessionManager implements ISessionManager {

	private IServer _system;
	private ConcurrentMap<Integer, ISession> _sessions;
	private Set<ISession> _anonSessions;
	private Logger _logger = Logger.getLogger(SessionManager.class.toString());
	public SessionManager(IServer system) {
		this._system = system;
		this._sessions = new ConcurrentHashMap<Integer, ISession>();
		this._anonSessions = new HashSet<ISession>();
	}
	
	@Override
	public ISession createSession(IConnection connection) {
		_logger.debug("Creating session for connection: "+connection.getID());
		ISession newSession = ServerFactory.createSession(connection, this._system);
		this._anonSessions.add(newSession);
		return newSession;
	}

	@Override
	public void closeSession(int userID) {
		updateSessions();
		ISession session = this._sessions.get(userID);
		if (session != null) {
			_logger.debug("Creating session of user:" + userID);
			session.close();
			this._sessions.remove(userID);
		}
	}

	@Override
	public void closeAll() {
		for (Iterator<Integer> iterator = this._sessions.keySet().iterator(); iterator.hasNext();) {
			Integer userID = (Integer) iterator.next();
			this._sessions.get(userID).close();
		}
		for (Iterator<ISession> iterator = this._anonSessions.iterator(); iterator.hasNext();) {
			ISession session = (ISession) iterator.next();
			session.close();
		}
		this._sessions.clear();
		this._anonSessions.clear();
	}

	@Override
	public boolean send(int userID, IPacket packet) {
		this.updateSessions();
		ISession session = this._sessions.get(userID);
		if (session != null) {
			return session.send(packet);
		}
		return false;
	}
	
	private synchronized void updateSessions() {
		HashSet<ISession> tmp = new HashSet<ISession>();
		for (ISession session: this._anonSessions) {
			if (session.isLoggedIn()) {
				tmp.add(session);
			}
		}
		for (ISession session: tmp) {
			this._anonSessions.remove(session);
			this._sessions.put(session.getUserID(), session);
		}
	}

	@Override
	public synchronized void sendNotification(INotification notification) {
		this.updateSessions();
		Collection<IUserStub> friends = this._system.getFriends(notification.getAuthorID());
		HashSet<Integer> friendIDs = new  HashSet<Integer>();
		for (IUserStub userStub: friends) {
			friendIDs.add(userStub.getID());
		}
		for (ISession session: this._sessions.values()) {
			if (session.getCurrentThreadID() == notification.getThreadID() || friendIDs.contains(session.getUserID())) {
				IPacket packet = SharedFactory.createPacket(EPacketType.ENotification);
				packet.addParam(EPacketParam.ENotification, notification);
				session.send(packet);
				_logger.info("Sent notification to"+session.getUserID());
			}
		}
	}
}
